;;; sniff-mode.el --- Minor mode for interacting with SNiFF+

;; Author: Gheorghe Chita <gil@TakeFive.co.at>
;; Maintainer: Josef Leherbauer <joe@TakeFive.co.at>
;; Created: 26 Jul 1993
;; Revision: 2.3
;; Keywords: tools sniff

;;; Commentary:

;; This file defines a minor mode to be used when editing C/C++ source files.
;; It creates a communication channel between Emacs and SNiFF+.

;; Usage
;; =====
;;	1) Load sniff-mode.el, or put a line like (load "sniff-mode") in
;;	   your .emacs file.
;;	2) Start SNiFF+ (v2.x) and enable Emacs in the Editor Preferences.
;;	3) M-x sniff-connect RET
;;	4) Load a project in SNiFF+ and double click on the desired symbol.
;;	   The corresponding file will be loaded in an Emacs buffer, and the
;;	   buffer will be put in Sniff mode.
;;
;;	   You can now use Sniff mode-specific commands. Do `C-h b'
;;	   (`describe-bindings') to see the new commands available.
;;	   Do `C-h k' (`describe-key') to get the documentation of the
;;	   individual commands.

;; Author: Gheorghe Chita
;;	TakeFive Software GesmbH
;;	Jakob Haringer Str. 8
;;	Salzburg, A-5020
;;	A U S T R I A
;;	Phone: +43 662 457 915
;;	Fax:   +43 662 457 915 6
;;	Email: gil@TakeFive.co.at

;;; Acknowledgements:

;; Thanks to Jordan K. Hubbard <jkh@whisker.lotus.ie> and
;; Michael Scharf <Michael.Scharf@embl-Heidelberg.de> for many useful ideas.
;;
;; The idea of using a buffer to gather bytes from a process until a regexp
;; is seen at the head of the buffer is taken from the transaction queue
;; library tq.el (thanks Scott Draves <spot@cs.cmu.edu>).
;;
;; The function sniff-symbol-around-point is the same as find-tag-default
;; in etags.el (thanks Roland McGrath <roland@gnu.ai.mit.edu>).

;;; Code:

(provide 'sniff-mode)

(defvar sniff-mode nil)
(make-variable-buffer-local 'sniff-mode)

(or (assq 'sniff-mode minor-mode-alist)
    (setq minor-mode-alist
	  (cons '(sniff-mode " Sniff") minor-mode-alist)))

(defvar sniff-mode-map ()
  "Keymap used in Sniff mode.")

(if sniff-mode-map
    ()
  (setq sniff-mode-map (make-sparse-keymap))
  (define-key sniff-mode-map "\C-c\C-e" 'sniff-toggle)
  (define-key sniff-mode-map "\C-c\C-s" 'sniff-superclass)
  (define-key sniff-mode-map "\C-c\C-o" 'sniff-overridden)
  (define-key sniff-mode-map "\C-c\C-r" 'sniff-retrieve)
  (define-key sniff-mode-map "\C-c\C-\M-r" 'sniff-retrieve-next)
  (define-key sniff-mode-map "\C-c\C-g" 'sniff-goto-symbol)
  (define-key sniff-mode-map "\C-c\C-f" 'sniff-find-symbol)
  (define-key sniff-mode-map "\C-c\C-b" 'sniff-browse-class)
  (define-key sniff-mode-map "\C-c\C-h" 'sniff-hierarchy)
  (define-key sniff-mode-map "\C-c\C-\M-h" 'sniff-restr-hier)
  (define-key sniff-mode-map "\C-c\C-x" 'sniff-xref-to)
  (define-key sniff-mode-map "\C-c\C-\M-x" 'sniff-xref-by)
  (define-key sniff-mode-map "\C-c\C-c" 'sniff-xref-has)
  (define-key sniff-mode-map "\C-c\C-\M-c" 'sniff-xref-usedby)
  (define-key sniff-mode-map "\C-c\C-d" 'sniff-show-docu)
  (define-key sniff-mode-map "\C-c\C-\M-d" 'sniff-gen-docu))

(or (assq 'sniff-mode minor-mode-map-alist)
    (setq minor-mode-map-alist
	  (cons (cons 'sniff-mode sniff-mode-map) minor-mode-map-alist)))

(defvar sniff-symbol-history nil
  "History of symbols entered in the minibuffer.")

(defconst sniff-is-xemacs (string-match "Lucid\\|XEmacs" emacs-version)
  "Non-nil means the running Emacs is a version of XEmacs or Lucid Emacs.")


;;; Symbol highlighting, font management

(defvar sniff-want-fonts t
  "*Non-nil means highlight symbols and comments according to sniff-font-table.")

(defvar sniff-font-table nil
  "*Vector of font codes. See sniff-mode.el for details.")

;; Change the table below to suit your needs.
(if sniff-font-table
    ()
  (setq sniff-font-table [
			  italic	; comment
			  bold		; macro
			  bold		; class, struct, union
			  bold-italic	; member variable
			  bold		; member function declaration
			  bold		; member function definition
			  bold		; function definition
			  bold		; friend
			  bold		; typedef
			  bold		; variable definition
			  bold		; constant
			  bold		; enum
			  bold		; enum item
			  bold		; user def object
			  ]))

(defun sniff-change-font (symbol-code from to)
  (if sniff-is-xemacs
      ;; XEmacs
      (let ((ext (make-extent from (1+ to))))
	(set-extent-property ext 'face (aref sniff-font-table symbol-code))
	(set-extent-property ext 'sniff t))
    ;; FSF Emacs
    (let ((ovl (make-overlay from (1+ to))))
      (overlay-put ovl 'face (aref sniff-font-table symbol-code))
      (overlay-put ovl 'sniff t))))

(defun sniff-delete-fonts ()
  "Delete fonts from the current buffer."
  (interactive)
  (if sniff-is-xemacs
      ;; XEmacs
      (map-extents (function (lambda (ext arg)
			       (if (extent-property ext 'sniff)
				   (delete-extent ext))
			       nil)))
    ;; FSF Emacs
    (let ((pos (next-overlay-change 1)) (max-pos (point-max)) ovl)
      (while (< pos max-pos)
 	(mapcar (function (lambda (ovl)
 			    (if (overlay-get ovl 'sniff)
				(delete-overlay ovl))
			    nil))
 		(overlays-at pos))
	(setq pos (next-overlay-change pos))))))


;;; Support for Japanese characters when running under MULE (MUlti Lingual Emacs)
 
;; Vector containing the buffer position of those (EUC or SJIS encoded)
;; multi-byte characters whose MULE-internal encoding requires one additional byte.
;; This is the case for Kanji characters in both encodings, for half-width Katakana
;; characters only in SJIS encoding. See `sniff-mule-make-table'.
;; The table is sorted in ascending order and recreated whenever the buffer is saved.
;;
(defvar sniff-mule-table nil)
(make-variable-buffer-local 'sniff-mule-table)
 
(defconst sniff-is-mule (fboundp 'mule-version)
  "Non-nil means the running Emacs is a version of MULE (MUlti Lingual Emacs).")

;; Sniff ---> MULE
;; Translate Sniff file position to MULE buffer position
(defun sniff-mule-xlate-down (pos)
  (if sniff-is-mule
      (let (i (shift 1) (low 0) (high (length (sniff-mule-make-table))))
	(while (and (< low high) (> shift 0))
	  (setq i (sniff-mule-find-pos pos low high)
		shift (- i low)
		pos (+ pos shift)
		low i))))
  pos)
 
;; Sniff <--- MULE
;; Translate MULE buffer position to Sniff file position
(defun sniff-mule-xlate-up (pos)
  (if sniff-is-mule
      (setq pos (- pos (sniff-mule-find-pos pos 0 (length (sniff-mule-make-table))))))
  pos)
 
;; Binary search `pos' in `sniff-mule-table' between indices `low' and `high'
;; Return index of first element which is >= `pos'
(defun sniff-mule-find-pos (pos low high)
  (let (i mb-pos)
    (while (progn (setq i (/ (+ low high) 2))
		  (< low high))
      (setq mb-pos (aref sniff-mule-table i))
      (cond ((> pos mb-pos) (setq low (1+ i)))
	    ((< pos mb-pos) (setq high i))
	    ((= pos mb-pos) (setq low i high i))))
    i))

;; Create the multi-byte translation table 
(defun sniff-mule-make-table ()
  (if sniff-mule-table
      ()
    (let ((i 1) (max-pos (buffer-size)) (tail (cons nil nil)) mb-flag
	  (is-sjis (eq file-coding-system '*sjis*unix)))
      (setq sniff-mule-table tail)
      (while (< i max-pos)
	(setq mb-flag (char-boundary-p i))
	(if (or (and (= mb-flag 1) is-sjis) ; 2-byte char (half-width Katakana)
		(= mb-flag 2))		    ; 3-byte char (Kanji)
	    (setq tail (setcdr tail (cons i nil))))
	(setq i (+ 1 i mb-flag)))
      (setq sniff-mule-table (vconcat (cdr sniff-mule-table)))))
  sniff-mule-table)
 

;;; The sniff process

(defvar sniff-process nil)

(defconst sniff-process-name "Sniff")
(defconst sniff-buffer-name  "*Sniff*")
(defconst sniff-comm	     "sniffemacs")

(defun sniff-connect ()
  "Open connection to SNiFF+."
  (interactive) 
  (cond ((not sniff-process)
	 (setq sniff-process
	       (start-process sniff-process-name sniff-buffer-name sniff-comm))
	 (set-process-filter sniff-process 'sniff-filter)
	 (set-process-sentinel sniff-process 'sniff-sentinel)
	 (process-kill-without-query sniff-process))))

(defun sniff-sentinel (process event)
  (sniff-filter process "")	; flush the message queue
  (setq sniff-process nil)
  (kill-buffer sniff-buffer-name))

(defun sniff-disconnect ()
  "Close connection to SNiFF+."
  (interactive)
  (if sniff-process
      (process-send-string sniff-process "q\n")))

(defun sniff-simple-request (request-code)
  (if sniff-process
      (process-send-string sniff-process
			   (format "%c%s\n" request-code (buffer-file-name)))))
 
(defun sniff-context-request (request-code symbol)
  (if (and sniff-process (> (length symbol) 0))
      (process-send-string sniff-process
			   (format "%c%s %d %s\n"
				   request-code
				   (buffer-file-name)
				   (sniff-mule-xlate-up (point))
				   symbol))))

(defsubst sniff-read-arg (prompt)
  (list (read-from-minibuffer prompt (sniff-symbol-around-point)
			      nil nil 'sniff-symbol-history)))

(defun sniff-mode (&optional arg)
  "Minor mode for editing C/C++ code with the help of SNiFF+.

Commands marked with a `*' read an argument from the minibuffer.
The string around point is inserted as the default argument.

Available commands:

\\<sniff-mode-map>* \\[sniff-goto-symbol]	Show the source code of a symbol.
* \\[sniff-superclass]	Show the baseclass of a class.
  \\[sniff-overridden]	Show the overridden method.
  \\[sniff-toggle]	Toggle declaration/implementation of a symbol.
* \\[sniff-browse-class]	Browse a class in the Class Browser.
* \\[sniff-hierarchy]	Show a class in the entire class hierarchy.
* \\[sniff-restr-hier]	Show the relatives of a class in the class hierarchy.
* \\[sniff-retrieve]	Retrieve from this file.
* \\[sniff-retrieve-proj]	Retrieve from this project.
* \\[sniff-retrieve-allprojs]	Retrieve from all projects.
  \\[sniff-retrieve-next]	Retrieve (using Retriever settings).
* \\[sniff-find-symbol]	Find all symbols matching a string.
* \\[sniff-xref-to]	Show refers-to relationships in the Cross Referencer.
* \\[sniff-xref-by]	Show referred-by relationships in the Cross Referencer.
* \\[sniff-xref-has]	Show has-a relationships in the Cross Referencer.
* \\[sniff-xref-usedby]	Show used-by relationships in the Cross Referencer.
* \\[sniff-show-docu]	Show the documentation of a symbol.
* \\[sniff-gen-docu]	Generate the documentation for a symbol."
  (interactive)
  (setq sniff-mode
	(if (null arg) (not sniff-mode)
	  (> (prefix-numeric-value arg) 0)))
  (if sniff-mode
      (progn
	(sniff-connect)
	(sniff-update)
	(and sniff-is-xemacs
	     current-menubar
	     (not (assoc "Sniff" current-menubar))
	     (add-menu nil "Sniff" sniff-mode-menu)))))

(defun sniff-filter (proc string)
  "Append STRING to Sniff's buffer; then process the new data."
  (let ((message nil))
    (save-excursion 
      (set-buffer sniff-buffer-name)
      (goto-char (point-max))
      (insert string)
      (setq message (sniff-process-buffer)))
    (while message
      (sniff-dispatch message)
      (save-excursion
	(set-buffer sniff-buffer-name)
	(setq message (sniff-process-buffer))))))
  
(defun sniff-process-buffer ()
  "Check current buffer for a new message."
  (goto-char (point-min))
  (if (re-search-forward "\\(.*\\)\n" nil t)
      (let ((message (buffer-substring (point-min) (1- (point)))))
	(delete-region (point-min) (point))
	message)))

(defun sniff-dispatch (string)
  "Extract the command and the arguments from the STRING."
  (let ((command (aref string 0))
	(arguments (substring string 1)))
    (cond ((or (= command ?o) (= command ?O))	; Open file, position at character/line
           (raise-frame)
	   (if (string-match "\\([^ ]+\\) \\([0-9]+\\) \\([0-9]+\\)" arguments)
	       (let* ((file-name (substring arguments
					    (match-beginning 1)
					    (match-end 1)))
		      (position (string-to-int (substring arguments
							  (match-beginning 2)
							  (match-end 2))))
		      (writable (string-to-int (substring arguments
							  (match-beginning 3)
							  (match-end 3))))
		      (file-buffer (find-file-noselect file-name)))
		 (let ((old-buf (current-buffer)))
		   (unwind-protect
		       (progn
			 (set-buffer file-buffer)
			 (setq buffer-read-only (= writable 0))
			 (if (not sniff-mode)
			     (sniff-mode 1))
			 (if (> position 0)
			     (if (= command ?o)
				 (goto-char (sniff-mule-xlate-down position))
			       (goto-line position))))
		     (set-buffer old-buf)))
		 (if (= (minibuffer-depth) 0)
		     (switch-to-buffer file-buffer)
		   ;;(display-buffer file-buffer)
		   (message "File %s loaded; type \"C-x b %s\" to view it."
			    (buffer-name file-buffer) (buffer-name file-buffer))))))

	  ((= command ?p)		; Path of a file has changed
	   (if (string-match "\\([^ ]+\\) \\([^ ]+\\)" arguments)
	       (let* ((old-file-name (substring arguments
						(match-beginning 1)
						(match-end 1)))
		      (new-file-name (substring arguments
						(match-beginning 2)
						(match-end 2)))
		      (already-loaded (get-file-buffer old-file-name)))
		 (if already-loaded
		     (save-excursion
		       (set-buffer already-loaded)
		       (delete-auto-save-file-if-necessary)
		       (set-visited-file-name new-file-name)
		       (set-buffer-modified-p nil)
		       (revert-buffer nil t)
		       (sniff-mode 1))))))
 
	  ((= command ?w)		; Writability of file has changed
	   (if (string-match "\\([^ ]+\\) \\([0-9]+\\)" arguments)
	       (let* ((file-name (substring arguments
					    (match-beginning 1)
					    (match-end 1)))
		      (writable (string-to-int
				 (substring arguments
					    (match-beginning 2)
					    (match-end 2))))
		      (already-loaded (get-file-buffer file-name)))
		 (if already-loaded
		     (save-excursion
		       (set-buffer already-loaded)
		       (setq buffer-read-only (= writable 0)))))))

	  ((= command ?h)		; Highlight info
	   (if (string-match "\\([^ ]+\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)" arguments)
	       (let* ((file-name (substring arguments
					    (match-beginning 1)
					    (match-end 1)))
		      (symbol-code (string-to-int (substring arguments
							     (match-beginning 2)
							     (match-end 2))))
		      (from (string-to-int (substring arguments
						      (match-beginning 3)
						      (match-end 3))))
		      (to (string-to-int (substring arguments
						    (match-beginning 4)
						    (match-end 4))))
		      (already-loaded (get-file-buffer file-name)))
		 (if already-loaded
		     (save-excursion
		       (set-buffer already-loaded)
		       (sniff-change-font symbol-code
					  (sniff-mule-xlate-down from)
					  (sniff-mule-xlate-down to)))))))

	  ((= command ?t)		; Tab width
	   (if (string-match "\\([^ ]+\\) \\([0-9]+\\)" arguments)
	       (let* ((file-name (substring arguments
					    (match-beginning 1)
					    (match-end 1)))
		      (already-loaded (get-file-buffer file-name)))
		 (if already-loaded
		     (save-excursion (set-buffer already-loaded)
				     (setq tab-width
					   (string-to-int
					    (substring arguments
						       (match-beginning 2)
						       (match-end 2)))))))))

	  ((or (= command ?a)		; Error message
	       (= command ?A))		; Warning message
	   (message "sniff: %s" arguments)))))

;;; Find and return the symbol around the point.
;;; Copied from etags.el.
(defun sniff-symbol-around-point ()
  "Return the string around point."
  (save-excursion
    (while (looking-at "\\sw\\|\\s_")
      (forward-char 1))
    (if (or (re-search-backward "\\sw\\|\\s_"
				(save-excursion (beginning-of-line) (point))
				t)
	    (re-search-forward "\\(\\sw\\|\\s_\\)+"
			       (save-excursion (end-of-line) (point))
			       t))
	(progn (goto-char (match-end 0))
	       (buffer-substring (point)
				 (progn (forward-sexp -1)
					(while (looking-at "\\s'")
					  (forward-char 1))
					(point))))
      nil)))


;;; Sniff requests
(setq sniff-fastsave nil)
 
(defun sniff-after-save ()
  (if sniff-mode
      (sniff-update))
  (setq sniff-mule-table nil))
(add-hook 'after-save-hook 'sniff-after-save)

(defun sniff-filechanged ()
  "Update file status."
  (interactive)
  (sniff-simple-request ?U))
 
(defun sniff-reparse ()
  "Reparse the file."
  (interactive)
  (sniff-simple-request ?u)
  (sniff-fonts))

(defun sniff-writebuffer ()
  "Save buffer w/o reparse."
  (interactive)
  (setq sniff-fastsave 1)
  (save-buffer)
  (setq sniff-fastsave nil))
 
(defun sniff-update ()
  ""
  (interactive)
  (sniff-filechanged)
  (if (not sniff-fastsave)
    (sniff-reparse)))
 
(defun sniff-fonts ()
  "Ask SNiFF+ to send font information."
  (interactive)
  (if (and window-system sniff-want-fonts)
      (progn
	(sniff-delete-fonts)
	(sniff-simple-request ?z))))

(defun sniff-toggle ()
  "Toggle between declaration and implementation."
  (interactive)
  (sniff-context-request ?e " "))

(defun sniff-superclass (symbol)
  "Show the Baseclass of a class."
  (interactive (sniff-read-arg "Show Baseclass Of: "))
  (sniff-context-request ?s symbol))

(defun sniff-overridden ()
  "Show Overridden Method."
  (interactive)
  (sniff-context-request ?m " "))

(defun sniff-retrieve (symbol)
  "Retrieve selection from this file."
  (interactive (sniff-read-arg "Retrieve: "))
  (sniff-context-request ?r symbol))

(defun sniff-retrieve-proj (symbol)
  "Retrieve selection from this project."
  (interactive (sniff-read-arg "Retrieve: "))
  (sniff-context-request ?p symbol))

(defun sniff-retrieve-allprojs (symbol)
  "Retrieve selection from all projects."
  (interactive (sniff-read-arg "Retrieve: "))
  (sniff-context-request ?P symbol))

(defun sniff-retrieve-next (symbol)
  "Retrieve selection (using Retriever settings)."
  (interactive (sniff-read-arg "Retrieve: "))
  (sniff-context-request ?R symbol))

(defun sniff-goto-symbol (symbol)
  "Show the source code of a symbol."
  (interactive (sniff-read-arg "Show Symbol: "))
  (sniff-context-request ?g symbol))

(defun sniff-find-symbol (symbol)
  "Find all symbols matching a string."
  (interactive (sniff-read-arg "Find Symbols Matching: "))
  (sniff-context-request ?f symbol))

(defun sniff-browse-class (symbol)
  "Browse a class in the Class Browser."
  (interactive (sniff-read-arg "Browse Class: "))
  (sniff-context-request ?w symbol))

(defun sniff-hierarchy (symbol)
  "Show a class in the entire class hierarchy."
  (interactive (sniff-read-arg "Show In Entire Hierarchy: "))
  (sniff-context-request ?t symbol))

(defun sniff-restr-hier (symbol)
  "Show the relatives of a class in the class hierarchy."
  (interactive (sniff-read-arg "Show Relatives In Hierarchy: "))
  (sniff-context-request ?T symbol))

(defun sniff-xref-to (symbol)
  "Show refers-to relationships in the Cross Referencer."
  (interactive (sniff-read-arg "Symbol Refers-to: "))
  (sniff-context-request ?x symbol))

(defun sniff-xref-by (symbol)
  "Show referred-by relationships in the Cross Referencer."
  (interactive (sniff-read-arg "Symbol Referred-by: "))
  (sniff-context-request ?X symbol))

(defun sniff-xref-has (symbol)
  "Show has-a relationships in the Cross Referencer."
  (interactive (sniff-read-arg "Symbol Refers-to Components: "))
  (sniff-context-request ?c symbol))

(defun sniff-xref-usedby (symbol)
  "Show used-by relationships in the Cross Referencer."
  (interactive (sniff-read-arg "Symbol Referred-by As Component: "))
  (sniff-context-request ?C symbol))

(defun sniff-show-docu (symbol)
  "Show the documentation of a symbol."
  (interactive (sniff-read-arg "Show Documentation Of: "))
  (sniff-context-request ?d symbol))

(defun sniff-gen-docu (symbol)
  "Generate the documentation for a symbol."
  (interactive (sniff-read-arg "Generate Documentation For: "))
  (sniff-context-request ?D symbol))

;;---------------------------------------------------
;; Menu Bar

(if sniff-is-xemacs

    ;; Menu for XEmacs
    (defvar sniff-mode-menu
      '(
	["Show Symbol ..."			sniff-goto-symbol t]
	["Show Baseclass Of ..."		sniff-superclass t]
	["Show Overridden Method"		sniff-overridden t]
	["Show Declaration/Implementation"		sniff-toggle t]
	"-"
	["Browse Class ..."			sniff-browse-class t]
	["Show In Entire Hierarchy ..."		sniff-hierarchy t]
	["Show Relatives In Hierarchy ..."	sniff-restr-hier t]
	"-"
	["Retrieve From This File..."		sniff-retrieve t]
	["Retrieve From This Project..."	sniff-retrieve-proj t]
	["Retrieve From All Projects..."	sniff-retrieve-allprojs t]
	["Retrieve (Using Retriever Settings)"			sniff-retrieve-next t]
	["Find Symbols Matching ..."		sniff-find-symbol t]
	"-"
	["Symbol Refers-to ..."			sniff-xref-to t]
	["Symbol Referred-by ..."			sniff-xref-by t]
	["Symbol Refers-to Components ..."	sniff-xref-has t]
	["Symbol Referred-by As Component ..."	sniff-xref-usedby t]
	"-"
	["Show Documentation Of ..."		sniff-show-docu t]
	["Generate Documentation For ..."	sniff-gen-docu t]
	"-"
	["Save w/o Reparse..."		sniff-writebuffer t]
	["Reparse..."	sniff-reparse t]
	"-"
	["Connect"		sniff-connect (not sniff-process)]
	["Disconnect"		sniff-disconnect sniff-process]
	)
      "XEmacs pulldown menu for Sniff mode.")

    ;; Menu for FSF Emacs
    (progn
      (define-key sniff-mode-map [menu-bar sniff]
	(cons "Sniff" (make-sparse-keymap "Sniff")))

      (define-key sniff-mode-map [menu-bar sniff disconnect]
	'("Disconnect" . sniff-disconnect))
      (define-key sniff-mode-map [menu-bar sniff connect]
	'("Connect" . sniff-connect))
      (define-key sniff-mode-map [menu-bar sniff separator-conn]
	'("--"))
 
      (define-key sniff-mode-map [menu-bar sniff reparse]
	'("Reparse ..." . sniff-reparse))
      (define-key sniff-mode-map [menu-bar sniff writebuffer]
	'("Save w/o Reparse" . sniff-writebuffer))
      (define-key sniff-mode-map [menu-bar sniff separator-save]
	'("--"))

      (define-key sniff-mode-map [menu-bar sniff gen-docu]
	'("Generate Documentation For ..." . sniff-gen-docu))
      (define-key sniff-mode-map [menu-bar sniff show-docu]
	'("Show Documentation Of ..." . sniff-show-docu))
      (define-key sniff-mode-map [menu-bar sniff separator-docu]
	'("--"))

      (define-key sniff-mode-map [menu-bar sniff xref-usedby]
	'("Symbol Referred-by as Component ..." . sniff-xref-usedby))
      (define-key sniff-mode-map [menu-bar sniff xref-has]
	'("Symbol Refers-to Components ..." . sniff-xref-has))
      (define-key sniff-mode-map [menu-bar sniff xref-by]
	'("Symbol Referred-by ..." . sniff-xref-by))
      (define-key sniff-mode-map [menu-bar sniff xref-to]
	'("Symbol Refers-to ..." . sniff-xref-to))
      (define-key sniff-mode-map [menu-bar sniff separator-xref]
	'("--"))

      (define-key sniff-mode-map [menu-bar sniff find-symbol]
	'("Find Symbols Matching ..." . sniff-find-symbol))
      (define-key sniff-mode-map [menu-bar sniff retrieve-next]
	'("Retrieve (Using Retriever Settings)" . sniff-retrieve-next))
      (define-key sniff-mode-map [menu-bar sniff retrieve-allprojs]
	'("Retrieve From All Projects ..." . sniff-retrieve-allprojs))
      (define-key sniff-mode-map [menu-bar sniff retrieve-proj]
	'("Retrieve From This Project ..." . sniff-retrieve-proj))
      (define-key sniff-mode-map [menu-bar sniff retrieve]
	'("Retrieve From This File ..." . sniff-retrieve))
      (define-key sniff-mode-map [menu-bar sniff separator-xref]
	'("--"))

      (define-key sniff-mode-map [menu-bar sniff restr-hierarchy]
	'("Show Relatives In Hierarchy ..." . sniff-restr-hier))
      (define-key sniff-mode-map [menu-bar sniff hierarchy]
	'("Show In Entire Hierarchy ..." . sniff-hierarchy))
      (define-key sniff-mode-map [menu-bar sniff browse-class]
	'("Browse Class ..." . sniff-browse-class))
      (define-key sniff-mode-map [menu-bar sniff separator-xref]
	'("--"))

      (define-key sniff-mode-map [menu-bar sniff toggle]
	'("Toggle Declaration/Implementation" . sniff-toggle))
      (define-key sniff-mode-map [menu-bar sniff overridden]
	'("Show Overridden Method" . sniff-overridden))
      (define-key sniff-mode-map [menu-bar sniff superclass]
	'("Show Baseclass Of ..." . sniff-superclass))
      (define-key sniff-mode-map [menu-bar sniff goto-symbol]
	'("Show Symbol(s) ..." . sniff-goto-symbol))

      (put 'sniff-connect 'menu-enable '(not sniff-process))
      (put 'sniff-disconnect 'menu-enable 'sniff-process)
      )
    )

;;; sniff-mode.el ends here
